package org.zjx.util;

import lombok.SneakyThrows;
import org.zjx.entity.Rect;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.*;

public class ImageUtil {

    public static BufferedImage cutImage(BufferedImage image, Rect rect) {
        BufferedImage subImage = image.getSubimage(rect.getLeft(), rect.getTop(), rect.getRight() - rect.getLeft() + 1, rect.getBottom() - rect.getTop() + 1);
        // 创建副本，以避免对原图像产生影响
        BufferedImage copy = new BufferedImage(subImage.getWidth(), subImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
        copy.getGraphics().drawImage(subImage, 0, 0, null);
        return copy;
    }

    @SneakyThrows
    public static BufferedImage stringToBufferedImage(String imageString){
        // 解码Base64字符串
        byte[] imageBytes = Base64.getDecoder().decode(imageString);
        // 将字节数组转回BufferedImage
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(imageBytes);
        return ImageIO.read(byteArrayInputStream);
    }


    @SneakyThrows
    public static String bufferedImageToString(BufferedImage image){
        // 将BufferedImage转换为ByteArrayOutputStream
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        // 将BufferedImage写入到ByteArrayOutputStream中
        ImageIO.write(image, "png", byteArrayOutputStream);
        // 获取字节数组
        byte[] imageBytes = byteArrayOutputStream.toByteArray();
        // 返回Base64编码的字符串
        return Base64.getEncoder().encodeToString(imageBytes);
    }


    public static boolean haveColor(BufferedImage image, List<Color> colors) {
        // 将颜色列表转换为HashSet以提高查找效率
        Set<Integer> targetRGBs = new HashSet<>();
        for (Color color : colors) {
            targetRGBs.add(color.getRGB());
        }

        int width = image.getWidth();
        int height = image.getHeight();

        // 遍历每个像素
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int pixelRGB = image.getRGB(x, y);
                // 检查像素颜色是否存在于目标颜色集合中
                if (targetRGBs.contains(pixelRGB)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取BufferedImage的中心点坐标
     * @param image 输入图像
     * @return 图像中心点坐标（基于图像像素坐标系）
     */
    public static Point getCenterPoint(BufferedImage image) {
        int centerX = image.getWidth() / 2;
        int centerY = image.getHeight() / 2;
        return new Point(centerX, centerY);
    }

    /**
     * 判断2个图片是否一样
     */
    public static boolean areImagesEqual(BufferedImage img1, BufferedImage img2) {
        if (img1 == img2) {
            return true; // 两个对象是同一个引用，直接返回 true
        }

        if (img1 == null || img2 == null) {
            return false; // 如果其中一个图片为空，返回 false
        }

        if (img1.getWidth() != img2.getWidth() || img1.getHeight() != img2.getHeight()) {
            return false; // 如果宽高不同，返回 false
        }

        // 比较每个像素的颜色值
        for (int x = 0; x < img1.getWidth(); x++) {
            for (int y = 0; y < img1.getHeight(); y++) {
                if (img1.getRGB(x, y) != img2.getRGB(x, y)) {
                    return false; // 如果发现有任何像素不相同，返回 false
                }
            }
        }

        return true; // 如果所有像素都相同，返回 true
    }


    /**
     *  缩小并去掉没有指定颜色区域
     * @param image 原始图片
     * @param colors 需要保留的颜色
     */
    public static BufferedImage cropAndResize(BufferedImage image, List<Color> colors) {
        // 1. 找到图像中符合颜色的区域
        int left = image.getWidth(), right = 0, top = image.getHeight(), bottom = 0;

        // 遍历图像，找到边界
        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                Color color = new Color(image.getRGB(x, y));
                if (isColorInList(color, colors)) {
                    // 更新边界
                    if (x < left) left = x;
                    if (x > right) right = x;
                    if (y < top) top = y;
                    if (y > bottom) bottom = y;
                }
            }
        }

        // 2. 截取符合颜色区域的图像
        return image.getSubimage(left, top, right - left + 1, bottom - top + 1);
    }

    // 判断颜色是否在指定的颜色列表中
    public static boolean isColorInList(Color color, List<Color> colors) {
        for (Color c : colors) {
            if (color.equals(c)) {
                return true;
            }
        }
        return false;
    }

    /**
     *  两幅图像的像素相同，则将结果图像的该位置的颜色设置为 img1 的颜色，否则设置为透明 (0, 0, 0, 0)。
     */
    public static BufferedImage compareImages(BufferedImage img1, BufferedImage img2) {
        // 获取图像的宽度和高度
        int width = img1.getWidth();
        int height = img1.getHeight();

        // 创建一个新的 BufferedImage，用于存储比较后的结果
        BufferedImage resultImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        // 遍历每个像素点，比较两幅图像的RGB值
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int rgb1 = img1.getRGB(x, y);  // 获取 img1 的像素值
                int rgb2 = img2.getRGB(x, y);  // 获取 img2 的像素值

                if (rgb1 == rgb2) {
                    // 如果两个图像的像素相同，保留原图像的颜色
                    resultImage.setRGB(x, y, rgb1);
                } else {
                    // 如果像素不同，设置透明
                    resultImage.setRGB(x, y, new Color(0, 0, 0, 0).getRGB());
                }
            }
        }

        return resultImage;
    }

    /**
     * 去异，把不相同的去掉
     */
    public static void deDifferent(BufferedImage image, BufferedImage image2) {
        if (image == null || image2 == null) {
            throw new NullPointerException("image or background is null");
        }
        if (image.getWidth() != image2.getWidth() || image.getHeight() != image2.getHeight()) {
            throw new IllegalArgumentException("Image dimensions don't match");
        }
        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                if (image.getRGB(x, y) != image2.getRGB(x, y)) {
                    image.setRGB(x, y, 0x00FFFFFF);
                }
            }
        }
    }

    /**
     * 指定颜色意外的图变为透明
     */
    public static BufferedImage makeColorsTransparent(BufferedImage image, List<Color> colorsToKeep) {
        if (image == null) {
            throw new IllegalArgumentException("Image cannot be null");
        }
        if (colorsToKeep == null) {
            throw new IllegalArgumentException("Color list cannot be null");
        }

        // 创建与原图相同类型和尺寸的新图像
        BufferedImage result = new BufferedImage(
                image.getWidth(),
                image.getHeight(),
                image.getType()
        );

        // 将原图绘制到新图像上
        Graphics2D g = result.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();

        // 提取颜色列表的ARGB值到集合中以便快速查找
        Set<Integer> argbSet = new HashSet<>();
        for (Color color : colorsToKeep) {
            argbSet.add(color.getRGB());
        }

        // 遍历每个像素进行处理
        int width = result.getWidth();
        int height = result.getHeight();
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int pixelArgb = result.getRGB(x, y);
                if (!argbSet.contains(pixelArgb)) {
                    // 设置alpha为0，保留RGB部分
                    int newPixelArgb = (0x00 << 24) | (pixelArgb & 0x00FFFFFF);
                    result.setRGB(x, y, newPixelArgb);
                }
            }
        }

        return result;
    }

    //region 快速查找图片,此方式是去掉透明比较，在透明多的时候效率高

    /**
     * 执行模板匹配，跳过透明区域
     */
    public static List<Point> matchTemplate(BufferedImage largeImage, BufferedImage smallImage) {
        List<Point> matchedLocations = new ArrayList<>();
        int largeWidth = largeImage.getWidth();
        int largeHeight = largeImage.getHeight();
        int smallWidth = smallImage.getWidth();
        int smallHeight = smallImage.getHeight();

        // 获取模板图像中的所有非透明像素位置
        List<Point> nonTransparentPixels = getNonTransparentPixels(smallImage);

        // 遍历大图进行模板匹配
        for (int y = 0; y <= largeHeight - smallHeight; y++) {
            for (int x = 0; x <= largeWidth - smallWidth; x++) {
                if (isMatch(largeImage, smallImage, x, y, nonTransparentPixels)) {
                    matchedLocations.add(new Point(x, y));
                }
            }
        }

        return matchedLocations;
    }

    /**
     * 获取模板图像中所有非透明像素位置
     */
    private static List<Point> getNonTransparentPixels(BufferedImage image) {
        List<Point> nonTransparentPixels = new ArrayList<>();
        int width = image.getWidth();
        int height = image.getHeight();

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int pixel = image.getRGB(x, y);
                if ((pixel & 0xFF000000) != 0) { // 判断是否为非透明像素
                    nonTransparentPixels.add(new Point(x, y));
                }
            }
        }

        return nonTransparentPixels;
    }

    /**
     * 判断当前区域是否与模板匹配（只比较非透明像素）
     */
    private static boolean isMatch(BufferedImage largeImage, BufferedImage smallImage, int startX, int startY, List<Point> nonTransparentPixels) {
        boolean match = true;

        // 对于每一个非透明像素点，比较大图相应位置的像素
        for (Point p : nonTransparentPixels) {
            int templateX = p.x;
            int templateY = p.y;
            int largeX = startX + templateX;
            int largeY = startY + templateY;

            int smallPixel = smallImage.getRGB(templateX, templateY);
            int largePixel = largeImage.getRGB(largeX, largeY);

            // 比较像素的颜色
            if (smallPixel != largePixel) {
                match = false;
                break;
            }
        }

        return match;
    }
    //endregion


}
